package com.karolak.client.fragments;

import java.awt.Font;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.swing.DefaultListSelectionModel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

public class TablePane extends JScrollPane {
	private static final long serialVersionUID = 1L;
	protected JTable table;
	private boolean valueChanged;

	public TablePane() {
		super();
		initialize();
	}

	protected void initialize() {
		setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
		setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		// setSize(200, 100);
		setColumnHeaderView(getTable().getTableHeader());
		setViewportView(getTable());
		getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
	}

	public JTable getTable() {
		if (table == null) {
			table = new JTable() {
				private static final long serialVersionUID = 1L;

				public boolean isCellEditable(int rowIndex, int vColIndex) {
					return false;
				}
			};
			// table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
			table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
			JTableHeader header = table.getTableHeader();
			header.setFont(new Font("Dialog", Font.BOLD, 12));
			table.setFont(new Font("Dialog", Font.BOLD, 12));

			table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
				public void valueChanged(ListSelectionEvent e) {
					setValueChanged(true);
				}
			});
			table.addMouseListener(new MouseAdapter() {
				@Override
				public void mouseReleased(MouseEvent e) {
					if (e.isPopupTrigger()) {
						return;
					}
					if (isValueChanged()) {
						setValueChanged(false);
					} else {
						getTable().clearSelection();
					}
				}
			});
		}
		return table;
	}

	public void setHeader(String header) {
		setHeaders(new String[] { header });
	}

	public void setHeaders(String[] headers) {
		if (headers == null) {
			return;
		}
		DefaultTableModel dataModel = (DefaultTableModel) getTable().getModel();
		for (String header : headers) {
			dataModel.addColumn(header);
		}
	}

	public Object[] getSelectedValues() {
		List<Object> selectedValues = new ArrayList<Object>();

		int[] ix = getTable().getSelectedRows();
		for (int i : ix) {
			Object o = getTable().getValueAt(i, 0);
			selectedValues.add(o);
		}
		return selectedValues.toArray();
	}

	@SuppressWarnings("unchecked")
	public <T> T getSelectedValue() {
		int[] ix = getTable().getSelectedRows();
		if (ix.length == 0) {
			return null;
		}
		return (T) getTable().getValueAt(ix[0], 0);
	}

	public String getSelectedString() {
		Object o = getSelectedValue();
		return o == null ? "" : o.toString();
	}

	public <T> void addObjectData(List<T> data) {
		if (data == null) {
			return;
		}

		ListSelectionListener[] listeners = removeSelectionListener();
		int columnCount = getTable().getColumnCount();
		for (T o : data) {
			List<T> row = new ArrayList<T>();
			for (int i = 0; i < columnCount; i++) {
				row.add(o);
			}
			addDataRow(row);
		}
		addSelectionListener(listeners);
	}

	public <T> void addData(List<List<T>> data) {
		if (data == null) {
			return;
		}
		for (List<T> dataRow : data) {
			addDataRow(dataRow);
		}
	}

	public <T> void addDataFrom1dList(List<T> data) {
		if (data == null) {
			return;
		}
		for (T dataRow : data) {
			List<T> row = new ArrayList<T>();
			row.add(dataRow);
			addDataRow(row);
		}
	}

	protected <T> void addDataRow(List<T> dataRow) {
		if (dataRow == null) {
			return;
		}
		DefaultTableModel dataModel = (DefaultTableModel) getTable().getModel();
		dataModel.addRow(new Vector<T>(dataRow));
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> getObjectData() {
		List<T> list = new ArrayList<T>();

		int count = getTable().getModel().getRowCount();
		for (int i = 0; i < count; i++) {
			T v = (T) getTable().getModel().getValueAt(i, 0);
			list.add(v);
		}
		return list;
	}

	public void removeData() {

		if (getTable().getSelectedRowCount() > 0) {
			getTable().clearSelection();
		}

		ListSelectionListener[] listeners = removeSelectionListener();

		DefaultTableModel dataModel = (DefaultTableModel) getTable().getModel();
		int rowCount = dataModel.getRowCount();
		for (int i = rowCount - 1; i > -1; i--) {
			dataModel.removeRow(i);
		}

		addSelectionListener(listeners);
	}

	protected ListSelectionListener[] removeSelectionListener() {
		DefaultListSelectionModel model = (DefaultListSelectionModel) getTable().getSelectionModel();
		ListSelectionListener[] listeners = model.getListSelectionListeners();
		for (ListSelectionListener listener : listeners) {
			model.removeListSelectionListener(listener);
		}
		return listeners;
	}

	protected void addSelectionListener(ListSelectionListener[] listeners) {
		if (listeners == null) {
			return;
		}
		ListSelectionModel model = getTable().getSelectionModel();
		for (ListSelectionListener listener : listeners) {
			model.addListSelectionListener(listener);
		}
	}

	@SuppressWarnings("unchecked")
	public void setSelectedObjectDataRow(Object o2) {
		List<Object> list = getObjectData();
		if (list == null || list.isEmpty()) {
			return;
		}

		int ix = 0;

		for (int i = 0; i < list.size(); i++) {
			Object o1 = list.get(i);

			if (o2 instanceof Map && o1 instanceof Map) {
				if (equals((Map) o1, (Map) o2)) {
					ix = i;
					break;
				}
			} else {
				if (equals(o1, o2)) {
					ix = i;
					break;
				}
			}
		}
		// getTable().getSelectionModel().setLeadSelectionIndex(ix);
		getTable().addRowSelectionInterval(ix, ix);
	}

	public void setObjectDataRow(Object data, int rowIx) {
		int columnCount = getTable().getColumnCount();
		List<Object> row = new ArrayList<Object>();
		for (int colIx = 0; colIx < columnCount; colIx++) {
			row.add(data);
			getTable().getModel().setValueAt(data, rowIx, colIx);
		}
	}

	protected boolean equals(Map<Object, Object> o1, Map<Object, Object> o2) {

		if (o1 == null && o2 == null) {
			return true;
		}
		if (o1.size() != o2.size()) {
			return false;
		}

		Iterator<Object> i = o1.keySet().iterator();
		while (i.hasNext()) {
			Object key = i.next();
			Object v1 = o1.get(key);
			Object v2 = o2.get(key);
			if (!equals(v1, v2)) {
				return false;
			}
		}
		return true;
	}

	protected boolean equals(Object o, Object o2) {

		if (o == null && o2 == null) {
			return true;
		}
		if (o == null) {
			return false;
		}
		if (o2 == null) {
			return false;
		}

		if (o instanceof String) {
			o = ((String) o).trim();
		}
		if (o2 instanceof String) {
			o2 = ((String) o2).trim();
		}
		return o.equals(o2);
	}

	public void setCellRenderer(TableCellRenderer cellRenderer) {

		TableColumnModel columnModel = getTable().getColumnModel();
		int columnCount = columnModel.getColumnCount();
		for (int i = 0; i < columnCount; i++) {
			TableColumn column = columnModel.getColumn(i);
			column.setCellRenderer(cellRenderer);
		}
	}

	public boolean isValueChanged() {
		return valueChanged;
	}

	public void setColumnWidths(int[] widths) {
		if (widths == null) {
			return;
		}
		int columnCount = getTable().getColumnCount();
		for (int i = 0; i < columnCount && i < widths.length; i++) {
			getTable().getColumnModel().getColumn(i).setPreferredWidth(widths[i]);
		}
	}

	public void setValueChanged(boolean valueChanged) {
		this.valueChanged = valueChanged;
	}
}